package com.clinic.accessor.db;

import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Component;

import com.clinic.entity.db.Drug;
import com.clinic.entity.db.DrugStock;
import com.clinic.entity.param.Index;
import com.clinic.entity.type.SortProperty;

@Component
public class DrugStockAccessor extends AbstractDbAccessor<DrugStock> {
	
	public DrugStock getDrugStockById(long id) {
		DetachedCriteria criteria = DetachedCriteria.forClass(DrugStock.class);
		criteria.add(Restrictions.eq(DrugStock.Columns.DRUG_STOCK_ID, id));
		return uniqueGeneric(criteria);
	}
	
	public List<DrugStock> getDrugStocksByDrugId(long drugId, Index index) {
		DetachedCriteria criteria = DetachedCriteria.forClass(DrugStock.class);
		criteria.add(Restrictions.eq("drug.drugId", drugId));
		return listGeneric(criteria, index);
	}
	
	public List<DrugStock> getAvailableDrugStocksByDrugId(long drugId, Index index) {
		DetachedCriteria criteria = DetachedCriteria.forClass(DrugStock.class);
		criteria.add(Restrictions.eq("drug.drugId", drugId));
		criteria.add(Restrictions.gt(DrugStock.Columns.STOCK_AMOUNT, 0));
		return listGeneric(criteria, index);
	}
	
	public List<DrugStock> getDrugStocksByTerm(String term, String column, Index index) {
		DetachedCriteria criteria = getCriteriaOfDrugStocksByTerm(term, column);
		if (SortProperty.EXPIRE_DATE.getColumn().equals(column) || 
				SortProperty.STOCK_AMOUNT.getColumn().equals(column)) {
			criteria.addOrder(Order.asc(column));
		}
		return listGeneric(criteria, index);
	}
	
	public List<DrugStock> getOutDatedDrugStocksByDate(Date date, Index index) {
		DetachedCriteria criteria = DetachedCriteria.forClass(DrugStock.class);
		criteria.add(Restrictions.lt(DrugStock.Columns.EXPIRE_DATE, date));
		return listGeneric(criteria, index);
	}

	public int countDrugStocksByTerm(String term) {
		DetachedCriteria criteria = getCriteriaOfDrugStocksByTerm(term);
		return getCount(criteria);
	}
	
	public DrugStock getDrugStockByDrugId(long drugId) {
		DetachedCriteria criteria = getCriteriaOfDrugStockByDrugId(drugId);
		return uniqueGeneric(criteria);
	}
	
	public int countDrugStockByDrugId(long drugId) {
		DetachedCriteria criteria = getCriteriaOfDrugStockByDrugId(drugId);
		return getCount(criteria);
	}
	
	public List<DrugStock> getDrugStocks(Index index) {
		DetachedCriteria criteria = getCriteriaOfDrugStocks();
		return listGeneric(criteria, index);
	}
	
	public int countDrugStocks() {
		DetachedCriteria criteria = getCriteriaOfDrugStocks();
		return getCount(criteria);
	}
	
	private DetachedCriteria getCriteriaOfDrugStocks() {
		DetachedCriteria criteria = DetachedCriteria.forClass(DrugStock.class);
		return criteria;
	}
	
	private DetachedCriteria getCriteriaOfDrugStockByDrugId(long drugId) {
		DetachedCriteria criteria = DetachedCriteria.forClass(DrugStock.class);
		criteria.add(Restrictions.eq("drug.drugId", drugId));
		return criteria;
	}
	
	private DetachedCriteria getCriteriaOfDrugStocksByTerm(String term) {
		return getCriteriaOfDrugStocksByTerm(term, StringUtils.EMPTY);
	}
	
	private DetachedCriteria getCriteriaOfDrugStocksByTerm(String term, String column) {
		DetachedCriteria subquery = DetachedCriteria.forClass(Drug.class, "d");
		subquery.add(Restrictions.ilike("d.name", "%" + term + "%"));
		subquery.setProjection(Projections.property("d.drugId"));	
		if (SortProperty.NAME.getColumn().equals(column)) {
			subquery.addOrder(Order.asc(column));
		}
		DetachedCriteria criteria = DetachedCriteria.forClass(DrugStock.class, "ds");
		criteria.add(Property.forName("ds.drug.drugId").in(subquery));
		return criteria;
	}
	
}
